package com.ybear.ybutils.utils;

import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.MediaStore;
import android.widget.TextView;

import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.palette.graphics.Palette;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ColorUtils {
    private static final float[] mHSV = new float[ 3 ];

    public static Palette.Builder getPaletteBuilder(@NonNull Bitmap bmp) {
        return Palette.from( bmp );
    }

    public static Palette getPalette(@NonNull Bitmap bmp) {
        return getPaletteBuilder( bmp ).generate();
    }

    /**
     * 获取图片的主色调
     * @param bmp           位图
     * @param hsv           hsv需要一个数组存储，传入null时默认使用内置的数组
     * <ul>
     *   <li><code>hsv[0]</code> is Hue \([0..360[\)</li>
     *   <li><code>hsv[1]</code> is Saturation \([0...1]\)</li>
     *   <li><code>hsv[2]</code> is Value \([0...1]\)</li>
     * </ul>
     * @param hsvSat        饱和度
     * @param hsvVal        亮度
     * @param defColor      默认颜色
     * @return              RGB色值
     */
    public static int getVibrantColor(@NonNull Bitmap bmp,
                                      @Nullable float[] hsv,
                                      @FloatRange(from = 0, to = 1) float hsvSat,
                                      @FloatRange(from = 0, to = 1) float hsvVal,
                                      @ColorInt int defColor) {
        // Vibrant （有活力）   Vibrant dark（有活力 暗色）   Vibrant light（有活力 亮色）
        // Muted （柔和）       Muted dark（柔和 暗色）      Muted light（柔和 亮色）
        int color = getPalette( bmp ).getVibrantColor( defColor );
        if( hsv == null ) hsv = mHSV;
        //转换为HSV
        Color.colorToHSV( color, hsv );
        hsv[ 1 ] = hsvSat;
        hsv[ 2 ] = hsvVal;
        //还原成RGB
        return Color.HSVToColor( hsv );
    }

    /**
     * 获取图片的主色调
     * @param bmp           位图
     * @param hsvSat        饱和度
     * @param hsvVal        亮度
     * @param defColor      默认颜色
     * @return              RGB色值
     */
    public static int getVibrantColor(@NonNull Bitmap bmp,
                                      @FloatRange(from = 0, to = 1) float hsvSat,
                                      @FloatRange(from = 0, to = 1) float hsvVal,
                                      @ColorInt int defColor) {
        return getVibrantColor( bmp, null, hsvSat, hsvVal, defColor );
    }

    /**
     * 获取图片的主色调
     * @param bmp           位图
     * @param hsvSat        饱和度
     * @param hsvVal        亮度
     * @return              RGB色值
     */
    public static int getVibrantColor(@NonNull Bitmap bmp,
                                      @FloatRange(from = 0, to = 1) float hsvSat,
                                      @FloatRange(from = 0, to = 1) float hsvVal) {
        return getVibrantColor( bmp, null, hsvSat, hsvVal, Color.WHITE );
    }

    /**
     * 获取图片的主色调 - 纯色
     * @param bmp           位图
     * @param defColor      默认颜色
     * @return              RGB色值
     */
    public static int getVibrantColor(@NonNull Bitmap bmp, @ColorInt int defColor) {
        return getVibrantColor( bmp, 1F, 1F, defColor );
    }

    /**
     * 获取图片的主色调 - 柔和（适合当主图的背景色）
     * @param bmp           位图
     * @param defColor      默认颜色
     * @return              RGB色值
     */
    public static int getMutedColor(@NonNull Bitmap bmp, @ColorInt int defColor) {
        return getVibrantColor( bmp, 0.1F, 1F, defColor );
    }

    /**
     * 获取图片的主色调
     * @param drawable      Drawable
     * @param canvas        需要被绘制的画布
     * @param hsv           hsv需要一个数组存储，传入null时默认使用内置的数组
     * <ul>
     *   <li><code>hsv[0]</code> is Hue \([0..360[\)</li>
     *   <li><code>hsv[1]</code> is Saturation \([0...1]\)</li>
     *   <li><code>hsv[2]</code> is Value \([0...1]\)</li>
     * </ul>
     * @param hsvSat        饱和度
     * @param hsvVal        亮度
     * @param defColor      默认颜色
     * @return              RGB色值
     */
    public static int getVibrantColor(Drawable drawable,
                                      @Nullable Canvas canvas,
                                      @Nullable float[] hsv,
                                      @FloatRange(from = 0, to = 1) float hsvSat,
                                      @FloatRange(from = 0, to = 1) float hsvVal,
                                      @ColorInt int defColor) {
        return getVibrantColor( toBitmap( drawable, canvas ), hsv, hsvSat, hsvVal, defColor );
    }

    /**
     * 获取图片的主色调
     * @param drawable      Drawable
     * @param canvas        需要被绘制的画布
     * @param hsvSat        饱和度
     * @param hsvVal        亮度
     * @param defColor      默认颜色
     * @return              RGB色值
     */
    public static int getVibrantColor(Drawable drawable,
                                      @Nullable Canvas canvas,
                                      @FloatRange(from = 0, to = 1) float hsvSat,
                                      @FloatRange(from = 0, to = 1) float hsvVal,
                                      @ColorInt int defColor) {
        return getVibrantColor( drawable, canvas, null, hsvSat, hsvVal, defColor );
    }

    /**
     * 获取图片的主色调
     * @param drawable      Drawable
     * @param canvas        需要被绘制的画布
     * @param hsvSat        饱和度
     * @param hsvVal        亮度
     * @return              RGB色值
     */
    public static int getVibrantColor(Drawable drawable,
                                      @Nullable Canvas canvas,
                                      @FloatRange(from = 0, to = 1) float hsvSat,
                                      @FloatRange(from = 0, to = 1) float hsvVal) {
        return getVibrantColor( drawable, canvas, null, hsvSat, hsvVal, Color.WHITE );
    }

    /**
     * 获取图片的主色调 - 纯色
     * @param drawable      Drawable
     * @param canvas        需要被绘制的画布
     * @param defColor      默认颜色
     * @return              RGB色值
     */
    public static int getVibrantColor(Drawable drawable,
                                @Nullable Canvas canvas, @ColorInt int defColor) {
        return getVibrantColor( drawable, canvas, 1F, 1F, defColor );
    }

    /**
     * 获取图片的主色调 - 柔和（适合当主图的背景色）
     * @param drawable      Drawable
     * @param canvas        需要被绘制的画布
     * @param defColor      默认颜色
     * @return              RGB色值
     */
    public static int getMutedColor(Drawable drawable,
                              @Nullable Canvas canvas, @ColorInt int defColor) {
        return getVibrantColor( drawable, canvas, 0.1F, 1F, defColor );
    }

    /**
     * Drawable转Bitmap
     * @param drawable      Drawable
     * @param canvas        需要被绘制的画布
     * @return              Bitmap
     */
    public static Bitmap toBitmap(Drawable drawable, @Nullable Canvas canvas) {
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        drawable.setBounds( 0, 0, width, height );
        // 创建bitmap
        Bitmap bitmap = Bitmap.createBitmap(
                width, height,
                drawable.getOpacity() != PixelFormat.OPAQUE ?
                        Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565
        );
        // 创建bitmap画布
        if( canvas == null ) canvas = new Canvas();
        //清空画布
        canvas.drawColor( Color.TRANSPARENT );
        canvas.setBitmap( bitmap );
        //绘制
        drawable.draw( canvas );
        return bitmap;
    }

    /**
     * Drawable转Bitmap
     * @param drawable      Drawable
     * @return              Bitmap
     */
    public static Bitmap toBitmap(Drawable drawable) {
        return toBitmap( drawable, new Canvas() );
    }

    /**
     * 图片的路径转图片
     * @param context       上下文
     * @param uri           图片的路径
     * @return              图片
     */
    public static Bitmap toBitmap(Context context, Uri uri) {
        Bitmap ret = null;
        ContentResolver cr = context.getContentResolver();
        try {
            ret = MediaStore.Images.Media.getBitmap( cr, uri );
        } catch (IOException e) {
            e.printStackTrace();
        }
        //另一种方法
        if( ret == null ) {
            try {
                ret = BitmapFactory.decodeStream( cr.openInputStream( uri ) );
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * 图片转Uri路径
     * @param context       上下文
     * @param bmp           转换的图片
     * @return              图片的路径
     */
    public static Uri toUri(Context context, Bitmap bmp) {
        return Uri.parse(MediaStore.Images.Media.insertImage(
                context.getContentResolver(),
                bmp,
                null,
                null
        ));
    }

    /**
     * 获取缩略图
     * @param bmp       获取缩略图的bmp
     * @param size      缩略图大小
     * @param isWidth   size是否为宽度，false为高度
     * @return          返回缩略图
     */
    public static Bitmap getThumbnail(@NonNull Bitmap bmp, int size, boolean isWidth) {
        int ar = Utils.calcAspectRatio( bmp.getWidth(), bmp.getHeight(), size, isWidth );
        return Bitmap.createScaledBitmap(
                bmp,
                isWidth ? size : ar,
                isWidth ? ar : size,
                true
        );
    }

    /**
     * 获取缩略图
     * @param bmp       获取缩略图的bmp
     * @return          返回缩略图
     */
    public static Bitmap getThumbnail(@NonNull Bitmap bmp) {
        return getThumbnail( bmp, 500, true );
    }

    /**
     * 通过uri获取缩略图
     * @param context       上下文
     * @param uri           原图的uri路径
     * @return              返回缩略图
     */
    public static Bitmap getThumbnail(final Context context, Uri uri) {
        //Uri转Bitmap
        Bitmap ret = toBitmap( context, uri );
        return ret != null ? getThumbnail( ret ) : null;
    }

    /**
     * bmp转字节数组
     * @param bmp           图片资源
     * @param needRecycle   允许被回收（长期持有建议true，否则容易抛异常）
     * @return              字节数组
     */
    public static byte[] bmpToByteArray(Bitmap bmp, boolean needRecycle) {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.PNG, 100, output);
        if (needRecycle) {
            bmp.recycle();
        }

        byte[] result = output.toByteArray();
        try {
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * bmp转字节数组
     * @param bmp           图片资源
     * @return              字节数组
     */
    public static byte[] bmpToByteArray(final Bitmap bmp) {
        return bmpToByteArray( bmp, true );
    }

    public @interface GradientType {
        int VERTICAL = 0;
        int HORIZONTAL = 1;
        int DIAGONAL = 2;
        int REVERSE_DIAGONAL = 3;
    }

    /**
     设置彩色文本
     @param view            需要设置的TextView
     @param colors          颜色数组            eg: [Color.RED, Color.GREEN, Color.BLUE]
     @param positions       颜色位置数组         eg: [0.3, 0.5, 0.2]
     @param type            渐变类型            eg: GradientType.VERTICAL
     */
    public static void setTextGradient(@NonNull TextView view,
                                       @NonNull @ColorInt int[] colors,
                                       @Nullable float[] positions,
                                       @GradientType int type) {
        Paint p = view.getPaint();
        int w = view.getWidth();
        int h = view.getHeight();
        if( w == 0 && h == 0 ) {
            view.measure( 0, 0 );
            w = view.getMeasuredWidth();
            h = view.getMeasuredHeight();
        }
        //长和宽求对角线长度
        int diagonal = ObjUtils.parseInt( Math.sqrt( w * w + h * h ) );
        float x0, y0, x1, y1;
        switch( type ) {
            case GradientType.VERTICAL:             //垂直渐变
                x0 = y0 = y1 = 0;
                x1 = h;
                break;
            case GradientType.DIAGONAL:             //对角线渐变
            case GradientType.REVERSE_DIAGONAL:     //反对角线渐变
                if( type == GradientType.DIAGONAL ) {
                    x0 = y0 = 0;
                    x1 = y1 = diagonal;
                }else {
                    x0 = y1 = diagonal;
                    x1 = y0 = 0;
                }
                break;
            default:                                //水平渐变
                x0 = y0 = y1 = 0;
                x1 = w;
                break;
        }
        p.setShader(
                new LinearGradient( x0, y0, x1, y1, colors, positions, Shader.TileMode.CLAMP )
        );
    }

    /**
     设置垂直渐变文本
     @param view            需要设置的TextView
     @param colors          颜色数组            eg: [Color.RED, Color.GREEN, Color.BLUE]
     @param positions       颜色位置数组         eg: [0.3, 0.5, 0.2]
     */
    public static void setTextGradientOfVertical(TextView view,
                                                 @NonNull @ColorInt int[] colors,
                                                 @Nullable float[] positions) {
        setTextGradient( view, colors, positions, GradientType.VERTICAL );
    }

    /**
     设置垂直渐变文本
     @param view            需要设置的TextView
     @param colors          颜色数组            eg: [Color.RED, Color.GREEN, Color.BLUE]
     */
    public static void setTextGradientOfVertical(TextView view,
                                                 @NonNull @ColorInt int[] colors) {
        setTextGradientOfVertical( view, colors, null );
    }

    /**
     设置水平渐变文本
     @param view            需要设置的TextView
     @param colors          颜色数组            eg: [Color.RED, Color.GREEN, Color.BLUE]
     @param positions       颜色位置数组         eg: [0.3, 0.5, 0.2]
     */
    public static void setTextGradientOfHorizontal(TextView view,
                                                   @NonNull @ColorInt int[] colors,
                                                   @Nullable float[] positions) {
        setTextGradient( view, colors, positions, GradientType.HORIZONTAL );
    }

    /**
     设置水平渐变文本
     @param view            需要设置的TextView
     @param colors          颜色数组            eg: [Color.RED, Color.GREEN, Color.BLUE]
     */
    public static void setTextGradientOfHorizontal(TextView view,
                                                   @NonNull @ColorInt int[] colors) {
        setTextGradientOfHorizontal( view, colors, null );
    }

    /**
     设置对角线渐变文本
     @param view            需要设置的TextView
     @param colors          颜色数组            eg: [Color.RED, Color.GREEN, Color.BLUE]
     @param positions       颜色位置数组         eg: [0.3, 0.5, 0.2]
     */
    public static void setTextGradientOfDiagonal(TextView view,
                                                 @NonNull @ColorInt int[] colors,
                                                 @Nullable float[] positions) {
        setTextGradient( view, colors, positions, GradientType.DIAGONAL );
    }

    /**
     设置对角线渐变文本
     @param view            需要设置的TextView
     @param colors          颜色数组            eg: [Color.RED, Color.GREEN, Color.BLUE]
     */
    public static void setTextGradientOfDiagonal(TextView view,
                                                 @NonNull @ColorInt int[] colors) {
        setTextGradientOfDiagonal( view, colors, null );
    }

    /**
     设置反对角线渐变文本
     @param view            需要设置的TextView
     @param colors          颜色数组            eg: [Color.RED, Color.GREEN, Color.BLUE]
     @param positions       颜色位置数组         eg: [0.3, 0.5, 0.2]
     */
    public static void setTextGradientOfReverseDiagonal(TextView view,
                                                        @NonNull @ColorInt int[] colors,
                                                        @Nullable float[] positions) {
        setTextGradient( view, colors, positions, GradientType.REVERSE_DIAGONAL );
    }

    /**
     设置反对角线渐变文本
     @param view            需要设置的TextView
     @param colors          颜色数组            eg: [Color.RED, Color.GREEN, Color.BLUE]
     */
    public static void setTextGradientOfReverseDiagonal(TextView view,
                                                        @NonNull @ColorInt int[] colors) {
        setTextGradientOfReverseDiagonal( view, colors, null );
    }

    /**
     * 取消渐变文本
     * @param textView      需要取消的TextView
     * @param defColor      取消后默认的颜色
     */
    public static void cancelTextGradient(TextView textView, @ColorInt int defColor) {
        Paint paint = textView.getPaint();
        paint.setShader( null );
        if( defColor != 0 ) textView.setTextColor( defColor );
    }

    /**
     * 取消渐变文本
     * @param textView      需要取消的TextView
     */
    public static void cancelTextGradient(TextView textView) {
        cancelTextGradient( textView, textView.getResources().getColor(R.color.colorDefBtn ));
    }

}
